﻿using System;
using System.Diagnostics;
using System.Linq;

namespace Cryptography.ECDSA.Internal.Secp256K1
{
    internal class Scalar
    {
        ///* Limbs of the secp256k1 order. */
        private const UInt32 N0 = 0xD0364141;
        private const UInt32 N1 = 0xBFD25E8C;
        private const UInt32 N2 = 0xAF48A03B;
        private const UInt32 N3 = 0xBAAEDCE6;
        private const UInt32 N4 = 0xFFFFFFFE;
        private const UInt32 N5 = Const.FFFFFFFF;
        private const UInt32 N6 = Const.FFFFFFFF;
        private const UInt32 N7 = Const.FFFFFFFF;

        ///* Limbs of 2^256 minus the secp256k1 order. */
        private const UInt32 NC0 = ~N0 + 1;
        private const UInt32 NC1 = ~N1;
        private const UInt32 NC2 = ~N2;
        private const UInt32 NC3 = ~N3;
        private const UInt32 NC4 = 1;

        ///* Limbs of half the secp256k1 order. */
        private const UInt32 NH0 = 0x681B20A0;
        private const UInt32 NH1 = 0xDFE92F46;
        private const UInt32 NH2 = 0x57A4501D;
        private const UInt32 NH3 = 0x5D576E73;
        private const UInt32 NH4 = Const.FFFFFFFF;
        private const UInt32 NH5 = Const.FFFFFFFF;
        private const UInt32 NH6 = Const.FFFFFFFF;
        private const UInt32 NH7 = 0x7FFFFFFF;

        public readonly UInt32[] D;


        public Scalar()
        {
            D = new UInt32[8];
        }

        public Scalar(UInt32[] arr)
        {
            D = arr;
        }

        public Scalar(Scalar other)
        {
            D = new UInt32[other.D.Length];
            Array.Copy(other.D, D, other.D.Length);
        }


        public Scalar Clone()
        {
            return new Scalar(this);
        }

        public static bool IsZero(Scalar r)
        {
            return r.D.All(t => t == 0);
        }

        public static void Mul(Scalar r, Scalar a, Scalar b)
        {
            var l = new UInt32[16];
            Mul512(l, a, b);
            Reduce512(r, l);
        }

        /// <summary>
        /// Add two scalars together(modulo the group order). Returns whether it overflowed.
        /// </summary>
        /// <param name="r"></param>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool Add(Scalar r, Scalar a, Scalar b)
        {
            UInt64 t = (UInt64)a.D[0] + b.D[0];
            r.D[0] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[1] + b.D[1];
            r.D[1] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[2] + b.D[2];
            r.D[2] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[3] + b.D[3];
            r.D[3] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[4] + b.D[4];
            r.D[4] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[5] + b.D[5];
            r.D[5] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[6] + b.D[6];
            r.D[6] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)a.D[7] + b.D[7];
            r.D[7] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            var overflow = t > 0 || CheckOverflow(r);
            Reduce(r, overflow);
            return overflow;
        }

        private static void Mul512(UInt32[] l, Scalar a, Scalar b)
        {
            /* 96 bit accumulator. */
            UInt32 c0 = 0, c1 = 0, c2 = 0;

            /* l[0..15] = a[0..7] * b[0..7]. */
            { UInt64 t = (UInt64)(a.D[0]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { l[0] = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[1]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[2]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[3]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[4]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[5]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[6]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[7]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[8]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[9]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[10]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[11]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[12]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[13]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (b.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { l[14] = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            Debug.Assert(c1 == 0);
            l[15] = c0;
        }

        private static void Reduce512(Scalar r, UInt32[] l)
        {
            UInt32 n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15];
            UInt32 m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;
            UInt32 p0, p1, p2, p3, p4, p5, p6, p7, p8;

            /* 96 bit accumulator. */
            UInt32 c0, c1, c2;

            /* Reduce 512 bits into 385. */
            /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */
            c0 = l[0]; c1 = 0; c2 = 0;
            { UInt64 t = (UInt64)(n0) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { (m0) = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[1]); c1 += (UInt32)((c0 < (l[1])) ? 1 : 0); Debug.Assert((c1 != 0) | (c0 >= (l[1]))); Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n1) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n0) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (m1) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[2]); UInt32 over = (UInt32)((c0 < (l[2])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n2) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n1) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n0) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (m2) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[3]); UInt32 over = (UInt32)((c0 < (l[3])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n3) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n2) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n1) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n0) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (m3) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[4]); UInt32 over = (UInt32)((c0 < (l[4])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n4) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n3) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n2) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n1) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n0); UInt32 over = (UInt32)((c0 < (n0)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m4) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[5]); UInt32 over = (UInt32)((c0 < (l[5])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n5) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n4) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n3) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n2) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n1); UInt32 over = (UInt32)((c0 < (n1)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m5) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[6]); UInt32 over = (UInt32)((c0 < (l[6])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n6) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n5) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n4) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n3) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n2); UInt32 over = (UInt32)((c0 < (n2)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m6) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (l[7]); UInt32 over = (UInt32)((c0 < (l[7])) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n7) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n6) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n5) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n4) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n3); UInt32 over = (UInt32)((c0 < (n3)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m7) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n7) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n6) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n5) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n4); UInt32 over = (UInt32)((c0 < (n4)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m8) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n7) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n6) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n5); UInt32 over = (UInt32)((c0 < (n5)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m9) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(n7) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n6); UInt32 over = (UInt32)((c0 < (n6)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (m10) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (n7); c1 += (UInt32)((c0 < (n7)) ? 1 : 0); Debug.Assert((c1 != 0) | (c0 >= (n7))); Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { (m11) = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            Debug.Assert(c0 <= 1);
            m12 = c0;

            /* Reduce 385 bits into 258. */
            /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */
            c0 = m0; c1 = 0; c2 = 0;
            { UInt64 t = (UInt64)(m8) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { (p0) = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m1); c1 += (UInt32)((c0 < (m1)) ? 1 : 0); Debug.Assert((c1 != 0) | (c0 >= (m1))); Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m9) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m8) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (p1) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m2); UInt32 over = (UInt32)((c0 < (m2)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m10) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m9) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m8) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (p2) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m3); UInt32 over = (UInt32)((c0 < (m3)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m11) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m10) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m9) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m8) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (p3) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m4); UInt32 over = (UInt32)((c0 < (m4)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m12) * (NC0); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m11) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m10) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m9) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m8); UInt32 over = (UInt32)((c0 < (m8)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (p4) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m5); UInt32 over = (UInt32)((c0 < (m5)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m12) * (NC1); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m11) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m10) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m9); UInt32 over = (UInt32)((c0 < (m9)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (p5) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m6); UInt32 over = (UInt32)((c0 < (m6)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m12) * (NC2); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m11) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m10); UInt32 over = (UInt32)((c0 < (m10)) ? 1 : 0); c1 += over; c2 += (UInt32)((c1 < over) ? 1 : 0); }
            //___________________________________________________________________________________________________________________________________

            { (p6) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m7); c1 += (UInt32)((c0 < (m7)) ? 1 : 0); Debug.Assert((c1 != 0) | (c0 >= (m7))); Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(m12) * (NC3); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { c0 += (m11); c1 += (UInt32)((c0 < (m11)) ? 1 : 0); Debug.Assert((c1 != 0) | (c0 >= (m11))); Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { (p7) = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            p8 = c0 + m12;
            Debug.Assert(p8 <= 2);

            /* Reduce 258 bits into 256. */
            /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */
            UInt64 c = p0 + (UInt64)NC0 * p8;

            r.D[0] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p1 + (UInt64)NC1 * p8;
            r.D[1] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p2 + (UInt64)NC2 * p8;
            r.D[2] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p3 + (UInt64)NC3 * p8;
            r.D[3] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p4 + (UInt64)p8;
            r.D[4] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p5;
            r.D[5] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p6;
            r.D[6] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;
            c += p7;
            r.D[7] = (UInt32)(c & 0xFFFFFFFF); c >>= 32;

            /* Final reduction of r. */
            var isOverflow = c > 0 || CheckOverflow(r);
            Reduce(r, isOverflow);
        }

        private static void Reduce(Scalar r, bool isOverflow)
        {
            UInt64 overflow = (UInt64)(isOverflow ? 1 : 0);
            UInt64 t = (UInt64)r.D[0] + overflow * NC0;
            r.D[0] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[1] + overflow * NC1;
            r.D[1] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[2] + overflow * NC2;
            r.D[2] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[3] + overflow * NC3;
            r.D[3] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[4] + overflow * NC4;
            r.D[4] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[5];
            r.D[5] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[6];
            r.D[6] = (UInt32)(t & Const.FFFFFFFF);
            t >>= 32;
            t += (UInt64)r.D[7];
            r.D[7] = (UInt32)(t & Const.FFFFFFFF);
        }

        private static bool CheckOverflow(Scalar a)
        {
            bool no = (a.D[7] < N7) || (a.D[6] < N6) || (a.D[5] < N5) || (a.D[4] < N4);
            bool yes = (a.D[4] > N4) & !no;
            no |= (a.D[3] < N3) & !yes;
            yes |= (a.D[3] > N3) & !no;
            no |= (a.D[2] < N2) & !yes;
            yes |= (a.D[2] > N2) & !no;
            no |= (a.D[1] < N1) & !yes;
            yes |= (a.D[1] > N1) & !no;
            yes |= (a.D[0] >= N0) & !no;
            return yes;
        }

        /// <summary>
        /// Compute the inverse of a scalar (modulo the group order).
        /// </summary>
        /// <param name="r"></param>
        /// <param name="x"></param>
        public static void Inverse(Scalar r, Scalar x)
        {
            int i;
            // First compute xN as x ^ (2^N - 1) for some values of N, and uM as x ^ M for some values of M.

            var u2 = new Scalar();
            Sqr(u2, x);
            var x2 = new Scalar();
            Mul(x2, u2, x);
            var u5 = new Scalar();
            Mul(u5, u2, x2);
            var x3 = new Scalar();
            Mul(x3, u5, u2);
            var u9 = new Scalar();
            Mul(u9, x3, u2);
            var u11 = new Scalar();
            Mul(u11, u9, u2);
            var u13 = new Scalar();
            Mul(u13, u11, u2);

            var x6 = new Scalar();
            Sqr(x6, u13);
            Sqr(x6, x6);
            Mul(x6, x6, u11);

            var x8 = new Scalar();
            Sqr(x8, x6);
            Sqr(x8, x8);
            Mul(x8, x8, x2);

            var x14 = new Scalar();
            Sqr(x14, x8);
            for (i = 0; i < 5; i++)
            {
                Sqr(x14, x14);
            }
            Mul(x14, x14, x6);

            var x28 = new Scalar();
            Sqr(x28, x14);
            for (i = 0; i < 13; i++)
            {
                Sqr(x28, x28);
            }
            Mul(x28, x28, x14);

            var x56 = new Scalar();
            Sqr(x56, x28);
            for (i = 0; i < 27; i++)
            {
                Sqr(x56, x56);
            }
            Mul(x56, x56, x28);

            var x112 = new Scalar();
            Sqr(x112, x56);
            for (i = 0; i < 55; i++)
            {
                Sqr(x112, x112);
            }
            Mul(x112, x112, x56);

            var x126 = new Scalar();
            Sqr(x126, x112);
            for (i = 0; i < 13; i++)
            {
                Sqr(x126, x126);
            }
            Mul(x126, x126, x14);

            /* Then accumulate the final result (t starts at x126). */
            var t = x126.Clone();
            for (i = 0; i < 3; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, u5); /* 101 */
            for (i = 0; i < 4; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 4; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, u5); /* 101 */
            for (i = 0; i < 5; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, u11); /* 1011 */
            for (i = 0; i < 4; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, u11); /* 1011 */
            for (i = 0; i < 4; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 5; i++)
            { /* 00 */
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 6; i++)
            { /* 00 */
                Sqr(t, t);
            }
            Mul(t, t, u13); /* 1101 */
            for (i = 0; i < 4; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, u5); /* 101 */
            for (i = 0; i < 3; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 5; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, u9); /* 1001 */
            for (i = 0; i < 6; i++)
            { /* 000 */
                Sqr(t, t);
            }
            Mul(t, t, u5); /* 101 */
            for (i = 0; i < 10; i++)
            { /* 0000000 */
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 4; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, x3); /* 111 */
            for (i = 0; i < 9; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, x8); /* 11111111 */
            for (i = 0; i < 5; i++)
            { /* 0 */
                Sqr(t, t);
            }
            Mul(t, t, u9); /* 1001 */
            for (i = 0; i < 6; i++)
            { /* 00 */
                Sqr(t, t);
            }
            Mul(t, t, u11); /* 1011 */
            for (i = 0; i < 4; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, u13); /* 1101 */
            for (i = 0; i < 5; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, x2); /* 11 */
            for (i = 0; i < 6; i++)
            { /* 00 */
                Sqr(t, t);
            }
            Mul(t, t, u13); /* 1101 */
            for (i = 0; i < 10; i++)
            { /* 000000 */
                Sqr(t, t);
            }
            Mul(t, t, u13); /* 1101 */
            for (i = 0; i < 4; i++)
            {
                Sqr(t, t);
            }
            Mul(t, t, u9); /* 1001 */
            for (i = 0; i < 6; i++)
            { /* 00000 */
                Sqr(t, t);
            }
            Mul(t, t, x); /* 1 */
            for (i = 0; i < 8; i++)
            { /* 00 */
                Sqr(t, t);
            }
            Mul(r, t, x6); /* 111111 */
        }

        public static bool IsEven(Scalar a)
        {
            return (a.D[0] & 1) < 1;
        }

        public static void SetB32(Scalar r, byte[] b32, ref bool overflow)
        {
            var isOverflow = SetB32(r, b32);
            if (overflow)
                overflow = isOverflow;
        }

        public static bool SetB32(Scalar r, byte[] b32)
        {
            r.D[0] = Util.BitToUInt32Invers(b32, 28);
            r.D[1] = Util.BitToUInt32Invers(b32, 24);
            r.D[2] = Util.BitToUInt32Invers(b32, 20);
            r.D[3] = Util.BitToUInt32Invers(b32, 16);
            r.D[4] = Util.BitToUInt32Invers(b32, 12);
            r.D[5] = Util.BitToUInt32Invers(b32, 8);
            r.D[6] = Util.BitToUInt32Invers(b32, 4);
            r.D[7] = Util.BitToUInt32Invers(b32, 0);

            var isOverflow = CheckOverflow(r);
            Reduce(r, isOverflow);
            return isOverflow;
        }

        public static bool SetB32(Scalar r, byte[] b32, int index)
        {
            r.D[0] = Util.BitToUInt32Invers(b32, index + 28);
            r.D[1] = Util.BitToUInt32Invers(b32, index + 24);
            r.D[2] = Util.BitToUInt32Invers(b32, index + 20);
            r.D[3] = Util.BitToUInt32Invers(b32, index + 16);
            r.D[4] = Util.BitToUInt32Invers(b32, index + 12);
            r.D[5] = Util.BitToUInt32Invers(b32, index + 8);
            r.D[6] = Util.BitToUInt32Invers(b32, index + 4);
            r.D[7] = Util.BitToUInt32Invers(b32, index + 0);

            var isOverflow = CheckOverflow(r);
            Reduce(r, isOverflow);
            return isOverflow;
        }

        /// <summary>
        /// Access bits from a scalar. All requested bits must belong to the same 32-bit limb.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public uint GetBits(int offset, int count)
        {
            if ((offset + count - 1) >> 5 != offset >> 5)
                throw new ArithmeticException();
            return (D[offset >> 5] >> (offset & 0x1F)) & (((uint)1 << count) - 1);
        }

        public static void Clear(Scalar r)
        {
            r.D[0] = 0;
            r.D[1] = 0;
            r.D[2] = 0;
            r.D[3] = 0;
            r.D[4] = 0;
            r.D[5] = 0;
            r.D[6] = 0;
            r.D[7] = 0;
        }

        public void SetInt(uint v)
        {
            D[0] = v;
            D[1] = 0;
            D[2] = 0;
            D[3] = 0;
            D[4] = 0;
            D[5] = 0;
            D[6] = 0;
            D[7] = 0;
        }

        //        public static uint GetBitsVar(Objects.Scalar a, int offset, int count)
        //        {
        //            Debug.Assert(count < 32);
        //            Debug.Assert(offset + count <= 256);
        //            if ((offset + count - 1) >> 5 == offset >> 5)
        //            {
        //                return GetBits(a, offset, count);
        //            }
        //            else
        //            {
        //                Debug.Assert((offset >> 5) + 1 < 8);
        //                return ((a.D[offset >> 5] >> (offset & 0x1F)) | (a.D[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((UInt32)1) << count) - 1);
        //            }
        //        }

        //        public static void CaddBit(Objects.Scalar r, uint ubit, int flag)
        //        {
        //            UInt64 t;
        //            Debug.Assert(ubit < 256);
        //            var bit = (byte)ubit;
        //            bit += (byte)((flag - 1) & 0x100);  /* forcing (bit >> 5) > 7 makes this a noop */
        //            t = (UInt64)r.D[0] + (((UInt32)(((bit >> 5) == 0) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[0] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[1] + (((UInt32)(((bit >> 5) == 1) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[1] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[2] + (((UInt32)(((bit >> 5) == 2) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[2] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[3] + (((UInt32)(((bit >> 5) == 3) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[3] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[4] + (((UInt32)(((bit >> 5) == 4) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[4] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[5] + (((UInt32)(((bit >> 5) == 5) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[5] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[6] + (((UInt32)(((bit >> 5) == 6) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[6] = (UInt32)(t & 0xFFFFFFFF); t >>= 32;
        //            t += (UInt64)r.D[7] + (((UInt32)(((bit >> 5) == 7) ? 1 : 0)) << (bit & 0x1F));
        //            r.D[7] = (UInt32)(t & 0xFFFFFFFF);
        //#if VERIFY
        //            Debug.Assert((t >> 32) == 0);
        //            Debug.Assert(CheckOverflow(r) == 0);
        //#endif
        //        }

        public static byte[] GetB32(Scalar a)
        {
            var bin = new byte[32];
            GetB32(bin, 0, a);
            return bin;
        }

        public static void GetB32(byte[] bin, int index, Scalar a)
        {
            bin[index + 0] = (byte)(a.D[7] >> 24);
            bin[index + 1] = (byte)(a.D[7] >> 16);
            bin[index + 2] = (byte)(a.D[7] >> 8);
            bin[index + 3] = (byte)(a.D[7]);

            bin[index + 4] = (byte)(a.D[6] >> 24);
            bin[index + 5] = (byte)(a.D[6] >> 16);
            bin[index + 6] = (byte)(a.D[6] >> 8);
            bin[index + 7] = (byte)(a.D[6]);

            bin[index + 8] = (byte)(a.D[5] >> 24);
            bin[index + 9] = (byte)(a.D[5] >> 16);
            bin[index + 10] = (byte)(a.D[5] >> 8);
            bin[index + 11] = (byte)(a.D[5]);

            bin[index + 12] = (byte)(a.D[4] >> 24);
            bin[index + 13] = (byte)(a.D[4] >> 16);
            bin[index + 14] = (byte)(a.D[4] >> 8);
            bin[index + 15] = (byte)(a.D[4]);

            bin[index + 16] = (byte)(a.D[3] >> 24);
            bin[index + 17] = (byte)(a.D[3] >> 16);
            bin[index + 18] = (byte)(a.D[3] >> 8);
            bin[index + 19] = (byte)(a.D[3]);

            bin[index + 20] = (byte)(a.D[2] >> 24);
            bin[index + 21] = (byte)(a.D[2] >> 16);
            bin[index + 22] = (byte)(a.D[2] >> 8);
            bin[index + 23] = (byte)(a.D[2]);

            bin[index + 24] = (byte)(a.D[1] >> 24);
            bin[index + 25] = (byte)(a.D[1] >> 16);
            bin[index + 26] = (byte)(a.D[1] >> 8);
            bin[index + 27] = (byte)(a.D[1]);

            bin[index + 28] = (byte)(a.D[0] >> 24);
            bin[index + 29] = (byte)(a.D[0] >> 16);
            bin[index + 30] = (byte)(a.D[0] >> 8);
            bin[index + 31] = (byte)(a.D[0]);
        }


        public static void Negate(Scalar r, Scalar a)
        {
            UInt32 nonzero = IsZero(a) ? 0 : 0xFFFFFFFF;
            UInt64 t = (UInt64)(~a.D[0]) + N0 + 1;
            r.D[0] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[1]) + N1;
            r.D[1] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[2]) + N2;
            r.D[2] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[3]) + N3;
            r.D[3] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[4]) + N4;
            r.D[4] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[5]) + N5;
            r.D[5] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[6]) + N6;
            r.D[6] = (UInt32)(t & nonzero); t >>= 32;
            t += (UInt64)(~a.D[7]) + N7;
            r.D[7] = (UInt32)(t & nonzero);
        }

        //        public static bool IsOne(Objects.Scalar a)
        //        {
        //            return ((a.D[0] ^ 1) | a.D[1] | a.D[2] | a.D[3] | a.D[4] | a.D[5] | a.D[6] | a.D[7]) == 0;
        //        }

        public static bool IsHigh(Scalar a)
        {
            bool yes = false;
            bool no = false;
            no |= (a.D[7] < NH7);
            yes |= (a.D[7] > NH7) & !no;
            no |= (a.D[6] < NH6) & !yes; /* No need for a > check. */
            no |= (a.D[5] < NH5) & !yes; /* No need for a > check. */
            no |= (a.D[4] < NH4) & !yes; /* No need for a > check. */
            no |= (a.D[3] < NH3) & !yes;
            yes |= (a.D[3] > NH3) & !no;
            no |= (a.D[2] < NH2) & !yes;
            yes |= (a.D[2] > NH2) & !no;
            no |= (a.D[1] < NH1) & !yes;
            yes |= (a.D[1] > NH1) & !no;
            yes |= (a.D[0] > NH0) & !no;
            return yes;
        }

        private static void Sqr(Scalar r, Scalar a)
        {
            var l = new UInt32[16];
            Sqr512(l, a);
            Reduce512(r, l);
        }

        private static void Sqr512(UInt32[] l, Scalar a)
        {
            /* 96 bit accumulator. */
            UInt32 c0 = 0, c1 = 0, c2 = 0;

            /* l[0..15] = a[0..7]^2. */
            { UInt64 t = (UInt64)(a.D[0]) * (a.D[0]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { l[0] = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________


            { (l[1]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[1]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[2]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[3]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[2]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[4]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________
            { UInt64 t = (UInt64)(a.D[0]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[5]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (a.D[3]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[6]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[0]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (a.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[7]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[1]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (a.D[4]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[8]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[2]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[9]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[3]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (a.D[5]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[10]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[4]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[11]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[5]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (a.D[6]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; c2 += (UInt32)((c1 < th) ? 1 : 0); Debug.Assert((c1 >= th) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[12]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[6]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)(t); UInt32 th2 = th + th; c2 += (UInt32)((th2 < th) ? 1 : 0); Debug.Assert((th2 >= th) || (c2 != 0)); UInt32 tl2 = tl + tl; th2 += (UInt32)((tl2 < tl) ? 1 : 0); c0 += tl2; th2 += (UInt32)((c0 < tl2) ? 1 : 0); c2 += (UInt32)((c0 < tl2) & (th2 == 0) ? 1 : 0); Debug.Assert((c0 >= tl2) || (th2 != 0) || (c2 != 0)); c1 += th2; c2 += (UInt32)((c1 < th2) ? 1 : 0); Debug.Assert((c1 >= th2) || (c2 != 0)); }
            //___________________________________________________________________________________________________________________________________

            { (l[13]) = c0; c0 = c1; c1 = c2; c2 = 0; }
            //___________________________________________________________________________________________________________________________________

            { UInt64 t = (UInt64)(a.D[7]) * (a.D[7]); UInt32 th = (UInt32)(t >> 32); UInt32 tl = (UInt32)t; c0 += (UInt32)tl; th += (UInt32)((c0 < tl) ? 1 : 0); c1 += th; Debug.Assert(c1 >= th); }
            //___________________________________________________________________________________________________________________________________

            { l[14] = c0; c0 = c1; c1 = 0; Debug.Assert(c2 == 0); }
            //___________________________________________________________________________________________________________________________________

            Debug.Assert(c1 == 0);
            l[15] = c0;
        }
    }
}